/*
 * Licensed Materials - Property of tenxcloud.com
 * (C) Copyright 2023 TenxCloud. All Rights Reserved.
 * 2023-04-08  @author xyinting
 */

package material

import (
	"cloud_android_backend/pkg/models/material"
	"cloud_android_backend/pkg/models/resources"
	"cloud_android_backend/pkg/utils"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"modules.tenxcloud.com/common/composite"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"k8s.io/klog/v2"
)

var (
	dufs_url = ""
	auth     = map[string]string{}
)

func init() {
	dufs_url = os.Getenv("DUFS_URL")

	auth["type"] = "basic"
	auth["username"] = os.Getenv("DUFS_USER")
	auth["password"] = os.Getenv("DUFS_PWD")

}

type DufsConfig struct {
	url  string
	auth map[string]string
}

func NewDufsConfig() *DufsConfig {
	ds := &DufsConfig{}
	ds.url = dufs_url
	ds.auth = auth
	return ds
}

func ListFile(path, name, order, sort string, from, size int) (*FileResponse2, error) {
	ds := NewDufsConfig()
	url := fmt.Sprintf("%s/%s", ds.url, path)
	query := map[string]interface{}{"json": ""}
	if name != "" {
		query["q"] = name
	}

	if order != "" && sort != "" {
		query["order"] = order
		query["sort"] = sort
	}

	_, body, err := utils.SendRequest("GET", url, ds.auth, query, nil, 10*time.Second)
	if err != nil {
		return nil, err
	}

	materialList := &material.FileResponse{}
	if err := json.Unmarshal(body, materialList); err != nil {
		klog.Errorf("parse body failed, error %v", err)
		return nil, err
	}

	materialList.Total = len(materialList.Paths)
	ret := FileResponse2{
		Href:     materialList.Href,
		Total:    materialList.Total,
		Children: []FileInfo2{},
	}
	if materialList.Total == 0 {
		return &ret, nil
	}

	//end := from + size
	//if materialList.Total < end {
	//	end = materialList.Total
	//}
	//if from >= end {
	//	from = end - 1
	//}
	//materialList.Paths = materialList.Paths[from:end]

	for _, material1 := range materialList.Paths {
		isDir := false
		if material1.PathType == "Dir" {
			isDir = true
		} else {
			//if (!strings.HasSuffix(material1.Name, ".mp4") &&
			//	!strings.HasSuffix(material1.Name, ".MP4") &&
			//	!strings.HasSuffix(material1.Name, ".braw") &&
			//	!strings.HasSuffix(material1.Name, ".MXF") &&
			//	!strings.HasSuffix(material1.Name, ".MOV") &&
			//	!strings.HasSuffix(material1.Name, ".MTS") &&
			//	!strings.HasSuffix(material1.Name, ".mov") &&
			//	!strings.HasSuffix(material1.Name, ".wav") &&
			//	!strings.HasSuffix(material1.Name, ".WAV") &&
			//	!strings.HasSuffix(material1.Name, ".mp3")) || strings.HasPrefix(material1.Name, ".") {
			//	continue
			//}
		}
		path1 := materialList.Href
		if path1 != "/" {
			path1 = path1 + "/" + material1.Name
		} else {
			path1 = path1 + material1.Name
		}
		time1 := time.UnixMilli(material1.Time)
		timeStr := time1.Format("2006-01-02 15:04:05")
		tmp := FileInfo2{
			Name:        material1.Name,
			IsDirectory: isDir,
			Time:        timeStr,
			Path:        path1,
			Size:        material1.Size,
		}
		ret.Children = append(ret.Children, tmp)
	}
	ret.Total = len(ret.Children)
	end := from + size
	if ret.Total < end {
		end = ret.Total
	}
	if from >= end && ret.Total != 0 {
		from = end - 1
	}

	ret.Children = ret.Children[from:end]
	return &ret, nil
}
func ListFileWithCategory(path, name, order, sort string, cat string, from, size int) (*FileResponse2, error) {
	ds := NewDufsConfig()
	url := fmt.Sprintf("%s/%s", ds.url, path)
	query := map[string]interface{}{"json": ""}
	if name != "" {
		query["q"] = name
	}

	if order != "" && sort != "" {
		query["order"] = order
		query["sort"] = sort
	}

	_, body, err := utils.SendRequest("GET", url, ds.auth, query, nil, 10*time.Second)
	if err != nil {
		return nil, err
	}

	materialList := &material.FileResponse{}
	if err := json.Unmarshal(body, materialList); err != nil {
		klog.Errorf("parse body failed, error %v", err)
		return nil, err
	}

	materialList.Total = len(materialList.Paths)
	dirSize, err := utils.DirSize("/fsdata" + path)
	if err != nil {
		klog.Errorf("get dir size failed, error %v", err)

	}
	ret := FileResponse2{
		Href:      materialList.Href,
		Total:     materialList.Total,
		TotalSize: utils.HumanSize(dirSize),
	}
	if materialList.Total == 0 {
		return &ret, nil
	}

	for _, material1 := range materialList.Paths {
		isDir := false
		if material1.PathType == "Dir" {
			isDir = true
		} else {
			time1 := time.UnixMilli(material1.Time)
			timeStr := time1.Format("2006-01-02 15:04:05")
			path1 := materialList.Href
			tmp := FileInfo2{
				Name:        material1.Name,
				IsDirectory: isDir,
				Time:        timeStr,
				Path:        path1,
				Size:        material1.Size,
			}
			switch cat {
			case "videos":
				if checkCat("videos", material1.Name) {

					ret.Children = append(ret.Children, tmp)
				} else {
					continue
				}
			case "apk":
				if checkCat("apk", material1.Name) {
					ret.Children = append(ret.Children, tmp)
				} else {
					continue
				}
			case "image":
				if checkCat("image", material1.Name) {
					ret.Children = append(ret.Children, tmp)
				} else {
					continue
				}
			case "document":
				if !checkCat("apk", material1.Name) &&
					!checkCat("videos", material1.Name) &&
					!checkCat("image", material1.Name) {
					ret.Children = append(ret.Children, tmp)
				} else {
					continue
				}
			default:
				ret.Children = append(ret.Children, tmp)
			}

		}

	}

	return &ret, nil
}
func checkCat(cat string, name string) bool {
	switch cat {
	case "videos":
		if strings.HasSuffix(name, ".mp4") ||
			strings.HasSuffix(name, ".MP4") ||
			strings.HasSuffix(name, ".braw") ||
			strings.HasSuffix(name, ".MXF") ||
			strings.HasSuffix(name, ".MOV") ||
			strings.HasSuffix(name, ".MTS") ||
			strings.HasSuffix(name, ".mov") ||
			strings.HasSuffix(name, ".wav") ||
			strings.HasSuffix(name, ".WAV") ||
			strings.HasSuffix(name, ".mp3") {

			return true
		} else {
			return false
		}
	case "apk":
		if strings.HasSuffix(name, ".apk") {
			return true
		} else {
			return false
		}
	case "image":
		if strings.HasSuffix(name, ".png") || strings.HasSuffix(name, ".jpg") || strings.HasSuffix(name, ".jpeg") || strings.HasSuffix(name, ".gif") || strings.HasSuffix(name, ".bmp") || strings.HasSuffix(name, ".webp") {
			return true
		} else {
			return false
		}
	}
	return false
}
func UploadDufs(file string, uid string) {

	body, err := ioutil.ReadFile(file)
	if err != nil {
		klog.Errorf("read file failed, error %v", err)
		return
	}
	ds := NewDufsConfig()
	name := filepath.Base(file)
	uploadPath := fmt.Sprintf("%s/%s/%s", ds.url, uid, name)
	if _, _, err := utils.SendRequest("PUT", uploadPath, ds.auth, nil, body, 30*time.Minute); err != nil {
		klog.Errorf("upload file failed, errror %v", err)
		return
	}

	dir, err := ioutil.ReadDir(filepath.Dir(file))
	for _, d := range dir {
		if err := os.RemoveAll(path.Join([]string{filepath.Dir(file), d.Name()}...)); err != nil {
			klog.Errorf("delete file failed, error %v", err)
			continue
		}
	}
	os.Remove(filepath.Dir(file))
}

func Delete(fPath string) error {

	fileList := strings.Split(fPath, ",")
	ds := NewDufsConfig()
	for _, file := range fileList {
		url := fmt.Sprintf("%s/%s", ds.url, file)
		if _, _, err := utils.SendRequest("DELETE", url, ds.auth, nil, nil, 5*time.Second); err != nil {
			klog.Errorf("delete file dailed, error %v", err)
			return err
		}
	}

	return nil
}

func DownloadFile(path string) ([]byte, error) {
	ds := NewDufsConfig()
	fileUrl := fmt.Sprintf("%s/%s", ds.url, path)
	klog.Infof("file url: %s", fileUrl)
	_, body, err := utils.SendRequest(http.MethodGet, fileUrl, ds.auth, nil, nil, 10*time.Second)
	if err != nil {
		klog.Error(err)
		return nil, err
	}
	return body, nil
}

type FileResponse2 struct {
	Href string `json:"path"` // 文件的路径
	//UriPrefix string `json:"uri_prefix"` // 文件服务的前缀， 一版为 '/'
	//HostAddr  string     `json:"host_addr"`  // 文件服务的URL
	Children  []FileInfo2 `json:"children"`
	Total     int         `json:"total"`
	TotalSize string      `json:"total_size"`
}

type FileInfo2 struct {
	IsDirectory bool   `json:"isDirectory"`
	Name        string `json:"name"`
	Time        string `json:"modifiedAt"`
	Size        int64  `json:"size"`
	Path        string `json:"path"`
}
type FileInfo struct {
	PathType string `json:"path_type"`
	Name     string `json:"name"`
	Time     int64  `json:"mtime"`
	Size     int64  `json:"size"`
}
type TransferFileReq struct {
	FileName []string `json:"file_name"`
	Devices  []int64  `json:"devices"`
}

func TransferFileToInstances(transfers TransferFileReq, uid string) error {
	db, err := composite.Database.GetOrm()
	if err != nil {
		klog.Errorf("get db failed, error %v", err)
		return err
	}
	instanceModel := resources.InstanceUses{}
	instances, err := instanceModel.GetListByIds(db, transfers.Devices)
	if err != nil {
		klog.Errorf("get instance failed, error %v", err)
		return err
	}
	for _, instance := range instances {
		adbAddr := fmt.Sprintf("%s:%d", instance.Instances.Machine.Ip, instance.Instances.AdbPort)
		for _, file := range transfers.FileName {
			localFile := fmt.Sprintf("/fsdata/%s/%s", uid, file)

			catDir := "Download"
			if checkCat("videos", file) {
				catDir = "Movies"
			}
			if checkCat("image", file) {
				catDir = "Pictures"
			}
			//if checkCat("apk", file) {
			//	catDir = "Documents"
			//} else if checkCat("videos", file) {
			//	catDir = "Movies"
			//} else if checkCat("image", file) {
			//	catDir = "Pictures"
			//} else {
			//	catDir = "Documents"
			//}
			distDir := fmt.Sprintf("/sdcard/%s/", catDir)
			err := utils.AdbPush(localFile, adbAddr, distDir)
			if err != nil {
				klog.Errorf("push file failed, error %v", err)
				return err
			}
		}
		err = utils.SyncMedia(adbAddr, "/sdcard")
		if err != nil {
			klog.Errorf("sync media failed, error %v", err)
			//return err
		}
	}

	return nil
}
